package com.soxing.braindata.web.controller.research;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.soxing.braindata.common.config.FileConfig;
import com.soxing.braindata.common.util.FileUtil;
import com.soxing.braindata.common.util.MatUtil;
import com.soxing.braindata.common.util.WebHelper;
import com.soxing.braindata.dao.domain.request.ExperimentSearchRequest;
import com.soxing.braindata.dao.domain.request.TesteeExperimentFileSearchRequest;
import com.soxing.braindata.dao.entity.Experiment;
import com.soxing.braindata.dao.entity.FileChunkInfo;
import com.soxing.braindata.dao.entity.TesteeExperimentFile;
import com.soxing.braindata.dao.service.IFileChunkInfoService;
import com.soxing.braindata.dao.service.ITesteeExperimentFileService;
import com.soxing.braindata.domain.enumeration.FileUploadTypeEnum;
import com.soxing.braindata.domain.vo.FileChunkVo;
import com.soxing.braindata.domain.vo.UploadResult;
import com.soxing.braindata.service.manager.ITesteeExperimentFileManager;
import com.soxing.braindata.service.manager.ITesteeExperimentManager;
import com.soxing.common.utils.response.MyPage;
import com.soxing.common.utils.response.WebResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.builder.ToStringExclude;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author :durango
 * @date :2022/7/30 10:58
 * @description 被试实验数据控制器
 */
@Slf4j
@RestController
@RequestMapping("/testee/file")
@Api(value = "被试实验数据管理", tags = {"被试实验数据管理"})
public class TesteeExperimentFileController {

    @Resource
    private FileConfig fileConfig;
    @Resource
    private IFileChunkInfoService fileChunkInfoService;
    @Resource
    private ITesteeExperimentFileService testeeExperimentFileService;

    @Resource
    private ITesteeExperimentFileManager testeeExperimentFileManager;



    @Value("${unzip.unzipPath}")
    private String unzipPath;

    /**
     * 上传文件块
     *
     * @param fileChunkInfo
     * @return
     */
    @ApiOperation(value = "上传文件块")
    @PostMapping("/chunk")
    public WebResponse<Boolean> uploadChunk(FileChunkVo fileChunkInfo) {
        MultipartFile file = fileChunkInfo.getUpfile();
        String fileName = file.getOriginalFilename();
        fileName = FileUtil.removeSpecialChar(fileName);
        log.info("file originName: {}, chunkNumber: {}", file.getOriginalFilename(), fileChunkInfo.getChunkNumber());
        try {
            byte[] bytes = file.getBytes();
            fileName = fileName + FileUtil.SPLIT + fileChunkInfo.getChunkNumber();
            String path = fileConfig.getAddress()
                    + FileUtil.SEPARATOR
                    + FileUploadTypeEnum.EXPERIMENT.getType()
                    + FileUtil.SEPARATOR
                    + fileChunkInfo.getIdentifier()
                    + FileUtil.SEPARATOR
                    + fileName;

            //文件写入指定路径

            String dir = fileConfig.getAddress()
                    + FileUtil.SEPARATOR
                    + FileUploadTypeEnum.EXPERIMENT.getType()
                    + FileUtil.SEPARATOR
                    + fileChunkInfo.getIdentifier();
            if (!Files.isWritable(Paths.get(dir))) {
                log.info("path not exist,create path: {}", Paths.get(dir));
                try {
                    Files.createDirectories(Paths.get(dir));
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }



            Files.write(Paths.get(path), bytes);
            fileChunkInfo.setFilePath(path);
            fileChunkInfo.setFileName(fileName);
            boolean flag = fileChunkInfoService.save(fileChunkInfo);
            return WebResponse.success(flag);
        } catch (IOException e) {
            String error = "上传" + fileName + "第" + fileChunkInfo.getChunkNumber() + "块异常";
            log.error(error, e);
            return WebResponse.fail(error);
        }
    }

    @ApiOperation(value = "检查已上传文件块的情况")
    @GetMapping("/chunk")
    public WebResponse<UploadResult> checkChunk(@RequestParam String identifier) {
        UploadResult ur = new UploadResult();
        List<TesteeExperimentFile> list = testeeExperimentFileService.list(new LambdaQueryWrapper<TesteeExperimentFile>().eq(TesteeExperimentFile::getIdentifier, identifier));
        if (!CollectionUtils.isEmpty(list)) {
            ur.setSkipUpload(true);
            ur.setLocation(list.get(0).getFilePath());
            return WebResponse.success(ur);
        }
        List<Integer> chunkNumberList = new ArrayList<>();
        ur.setUploadedChunks(chunkNumberList);
        ur.setSkipUpload(false);

        List<FileChunkInfo> fileChunkInfoList = fileChunkInfoService.list(new LambdaQueryWrapper<FileChunkInfo>().eq(FileChunkInfo::getIdentifier, identifier));
        if (CollectionUtils.isEmpty(fileChunkInfoList)) {
            return WebResponse.success(ur);
        }
        fileChunkInfoList.forEach(fileChunkInfo1 -> {
            chunkNumberList.add(fileChunkInfo1.getChunkNumber());
        });
        return WebResponse.success(ur);
    }

    /**
     * 返回合并后实验文件的主键ID
     *
     * @param fileChunkInfo
     * @return
     */
    @ApiOperation(value = "文件块已上传完成,合并文件块")
    @PostMapping("/mergeFile")
    public WebResponse<Integer> mergeFile(@RequestBody FileChunkInfo fileChunkInfo) {
        TesteeExperimentFile testeeExperimentFile = new TesteeExperimentFile();
        testeeExperimentFile.setFileName(fileChunkInfo.getFileName());
        testeeExperimentFile.setIdentifier(fileChunkInfo.getIdentifier());
        testeeExperimentFile.setTotalSize(fileChunkInfo.getTotalSize());
        testeeExperimentFile.setCreatePin(WebHelper.getUserNum());
        testeeExperimentFile.setCreateTime(new Date());

        String fileName = FileUtil.removeSpecialChar(fileChunkInfo.getFileName());
        String path = fileConfig.getAddress()
                + FileUtil.SEPARATOR
                + FileUploadTypeEnum.EXPERIMENT.getType()
                + FileUtil.SEPARATOR
                + fileChunkInfo.getIdentifier()
                + FileUtil.SEPARATOR
                + fileName;
        testeeExperimentFile.setFilePath(path);
        testeeExperimentFile.setTag("0");

        File file = new File(path);
        boolean flag = FileUtil.merge(file.getParent(), file.getName(), path);
        if (flag) {

            //如果之前上传过文件的话，直接查询md5，获得QA值
            List<TesteeExperimentFile> list =testeeExperimentFileService.list(new LambdaQueryWrapper<TesteeExperimentFile>().eq(TesteeExperimentFile::getIdentifier, testeeExperimentFile.getIdentifier()));
            if (!CollectionUtils.isEmpty(list)) {
                testeeExperimentFile.setQa(list.get(0).getQa());
            }
            else{
                float QA = MatUtil.read(path,unzipPath);
                testeeExperimentFile.setQa(QA);
            }
            testeeExperimentFileService.save(testeeExperimentFile);
            //return WebResponse.success(testeeExperimentFile.getId());
            return WebResponse.success(testeeExperimentFile);
        } else {
            return WebResponse.fail("合并失败");
        }
    }

    @GetMapping("/download")
    @ApiOperation(value = "下载文件")
    public void download(HttpServletRequest request, HttpServletResponse response,@RequestParam String filePath) throws IOException {
        File a = new File(filePath);
        FileUtil.downloadBigFile(request,response,a);
    }

//    @GetMapping("/testDownload")
//    public int testDownload(HttpServletRequest request, HttpServletResponse response) throws IOException {
//        File a = new File("/export/data/braindata/experiment/3f6f76212ae3637f6f0988210fd60eb5/rhnaeh_Orthography_EEG_prepro_ERP.zip");
//        FileUtil.downloadBigFile(request,response,a);
//        return 0;
//    }


    @PostMapping("/search")
    @ApiOperation(value = "基于条件查询文件")
    public WebResponse<MyPage<TesteeExperimentFile>> search(@RequestBody(required = false) TesteeExperimentFileSearchRequest testeeExperimentFileSearchRequest) {
        if (testeeExperimentFileSearchRequest == null) {
            testeeExperimentFileSearchRequest = new TesteeExperimentFileSearchRequest();
        }
        return testeeExperimentFileManager.search(testeeExperimentFileSearchRequest);
    }


    @PutMapping
    @ApiOperation(value = "更新文件信息")
    public WebResponse<Boolean> update(TesteeExperimentFile testeeExperimentFile) {
        if (testeeExperimentFile.getId() == null) {
            return WebResponse.fail("主键ID为空");
        }
        return testeeExperimentFileManager.update(testeeExperimentFile);
    }


    @GetMapping("/{id}")
    @ApiOperation(value = "基于id获取文件信息")
    public WebResponse<TesteeExperimentFile> getById(@PathVariable("id") Integer id) {
        return testeeExperimentFileManager.getById(id);
    }

    @PostMapping("/delete/{id}")
    @ApiOperation(value = "基于id删除实验记录")
    public WebResponse<Boolean> deleteById(@PathVariable("id") Integer id) {
        return testeeExperimentFileManager.deleteById(id);
    }





}
